package bot;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CyclicBarrier;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Head extends Thread {
	protected static final Logger LOCAL_LOG = LogManager
			.getLogger(LogManager.ROOT_LOGGER_NAME);

	private final CyclicBarrier barrier;

	private final Leg[] legs;

	public Head(CyclicBarrier barrier, Leg... legs) {
		setName("HEAD");
		this.legs = legs;
		this.barrier = barrier;
	}

	private final ConcurrentLinkedQueue<Throwable> exQueue = new ConcurrentLinkedQueue<Throwable>();

	@Override
	public void run() {
		// check if legs are launched
		// checkLeg(legs);
		try {
			LOCAL_LOG.info(getName()+" is waiting for leg's start");
			this.barrier.await();
		} catch (InterruptedException e1) {
			LOCAL_LOG.fatal(e1.getMessage(), e1);
			interrupt();
			System.exit(0);
		} catch (BrokenBarrierException e1) {
			LOCAL_LOG.fatal(e1.getMessage(), e1);
		}

		Leg current = legs[0];
		for (int i = 1; i <= 100; i++) {
			current.move(i,this);
			synchronized (current) {
				while (0 == current.getResult())
					try {
						if (LOCAL_LOG.isInfoEnabled())
							LOCAL_LOG.info(getName()+" is waiting for "
									+ current.getName() + " make step " + i);
						current.wait();
					} catch (InterruptedException e) {
						Thread.currentThread().interrupt();
					}
				if(1==current.getResult())
					if (LOCAL_LOG.isInfoEnabled())
						LOCAL_LOG.info(current.getName() + " made step " + i);
					else;
				else
					LOCAL_LOG.info(current.getName() + " FAIL! #"+i);
			}
			// to move step-by-step
//			if (!deque.isEmpty() & LOCAL_LOG.isErrorEnabled())
//				LOCAL_LOG.error(current.getTittle()
//						+ extractException().getMessage());
			// try {
			// //take pause for better test in console
			// sleep(2000);
			// } catch (InterruptedException e) {
			// interrupt();
			// }
			if (current == legs[0])
				current = legs[1];
			else
				current = legs[0];
		}
		try {
			for(Leg leg:this.legs){
			leg.turnOn.set(false);
			leg.interrupt();
			leg.join();
			}

			for(Throwable t:exQueue)
				LOCAL_LOG.warn(t.getMessage(), t);
		} catch (InterruptedException e) {
			LOCAL_LOG.error(e.getLocalizedMessage(), e);
		} finally {
			throw new RuntimeException("Kamikaze");
		}
	}

	public void checkLeg(Leg... legs) {
		for (Leg leg : legs)
			synchronized (leg) {
				while (!leg.isAlive())
					try {

						leg.wait();
					} catch (InterruptedException e) {
						Thread.currentThread().interrupt();
					}
			}
	}

	public boolean addException(Throwable throwable) {
		return exQueue.offer(throwable);
	}

	public Throwable extractException() {
		return exQueue.poll();
	}
}
